﻿using Avalon.Core.MVC.Attributes;
using Avalon.Core.Resources;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

namespace Avalon.Core.Data.Templates
{
    public class AvalonView : BaseAuditableEntity
    {
        public string Name { get; set; }
        public string AvalonViewRendererGroupName { get; set; }
        public string AvalonViewRendererName { get; set; }
        public string ActionName { get; set; }
        public string ActionAlias { get; set; }
        public Dictionary<string, object> Params { get; set; }

        public string AssemblyQualifiedName { get; set; }
        public string ViewTypeName { get; set; }

        [Parent]
        public virtual AvalonEntity Entity { get; set; }
        public virtual AvalonViewRenderer ViewRenderer { get; set; }
        public virtual ICollection<AvalonViewField> Fields { get; set; }

        public AvalonView()
        {
            Fields = new HashSet<AvalonViewField>();
        }

        public static AvalonView Create(Type viewModelType, AvalonView view) {
            if (view == null) {
                view = new AvalonView();

                view.Name = viewModelType.Name;
                view.ViewTypeName = viewModelType.Name;
                view.AssemblyQualifiedName = viewModelType.AssemblyQualifiedName;

                ViewModelAttribute viewModelAttribute = viewModelType.GetCustomAttribute<ViewModelAttribute>(true);
                if (viewModelAttribute == null) throw new Exception(AvalonResources.EntityProvider_DataModelTypeNotImplemented);

                view.AvalonViewRendererGroupName = string.IsNullOrWhiteSpace(viewModelAttribute.ViewRendererGroupName) ? "Default" : viewModelAttribute.ViewRendererGroupName;
                AvalonViewRendererGroup group = RepositoryConfig.Initialize<AvalonViewRendererGroup>().Get().FirstOrDefault(g => g.Name == view.AvalonViewRendererGroupName);
                if (group != null) {

                    AvalonViewRenderer renderer = group.AvalonViewRenderers.FirstOrDefault(r => string.Format(r.Template, viewModelAttribute.DataModelType.Name) == view.Name);
                    if (renderer != null) {
                        view.AvalonViewRendererGroupName = group.Name;
                        view.AvalonViewRendererName = renderer.Name;
                        view.ActionName = renderer.Action;
                        view.ActionAlias = renderer.Action;
                        view.ViewRenderer = renderer;
                    }
                    else {
                        if (view.Name == string.Format(group.DefaultTemplate, viewModelAttribute.DataModelType.Name)) {
                            view.AvalonViewRendererGroupName = group.Name;
                            view.AvalonViewRendererName = "DefaultTempalte";
                            view.ActionName = "Unknown";
                            view.ActionAlias = "Unknown";
                            view.ViewRenderer = null;
                        }
                    }
                }
            }

            //set entity fields
            foreach (PropertyInfo pInfo in viewModelType.GetProperties()) {
                AvalonViewField field = view.Fields.FirstOrDefault(ef => ef.Name == pInfo.Name);
                if (field == null) {
                    field = new AvalonViewField();
                    field.IsParent = false;
                    field.IsChildCollection = false;
                    field.IsIEntity = false;

                    field.Title = pInfo.Name;
                    field.Name = pInfo.Name;
                    DisplayAttribute display = pInfo.GetCustomAttribute<DisplayAttribute>();
                    if (display != null) {
                        field.Title = display.Name;
                        field.GroupName = display.GroupName;
                        field.Order = display.GetOrder() ?? 0;
                    }

                    field.FieldType = FieldType.Text;

                    field.RenderMode = RenderMode.Any;
                    RenderModeAttribute renderMode = pInfo.GetCustomAttribute<RenderModeAttribute>();
                    if (renderMode != null) {
                        field.RenderMode = renderMode.RenderMode;
                    }

                    //If the property is decorated with a parent property
                    ParentAttribute parent = pInfo.GetCustomAttribute<ParentAttribute>();
                    if (parent != null) {
                        field.IsParent = true;
                        field.AssemblyQualifiedName = pInfo.PropertyType.AssemblyQualifiedName;
                    }

                    //If the property is a child collection
                    if (pInfo.PropertyType.IsGenericType && pInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)) {
                        field.IsChildCollection = true;
                        field.AssemblyQualifiedName = pInfo.PropertyType.AssemblyQualifiedName;
                    }

                    //If the property is an ientity
                    if (typeof(IEntity).IsAssignableFrom(pInfo.PropertyType)) {
                        field.IsIEntity = true;
                    }

                    //add the view field to the view
                    view.Fields.Add(field);
                }
            }

            return view;
        }
    }
}
